﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace Query2Object
{
    class SqlSession:ISession
    {
        private IDbContext context;

        private SqlConnection conn;

        private SqlCommand comm;

        private SqlDataReader rd;

        private SqlTransaction trans;

        #region ISession 成员

        public IDbContext Context
        {
            get
            {
                return context;
            }
            set
            {
                context = value;
            }
        }
        public void Init(string ConnectionString)
        {
            conn = new SqlConnection(ConnectionString);
            if (conn.State == ConnectionState.Closed)
            {
                conn.Open();
            }
        }

        public IQuery GetQuery(IQueryable QueryParam)
        {
            IQuery query = new SqlQuery();
            query.Session = this;
            query.From(QueryParam);
            return query;
        }

        public bool GetSingle(IQueryable Key)
        {
            string Sql = "SELECT * FROM [" + Key._ObjectTableName + "] WHERE [" + Key._PrimaryKeyName + "] = @" + Key._PrimaryKeyName;
            PrepareCommand(Sql, Key);
            using (rd = comm.ExecuteReader())
            {
                if (rd.Read())
                {
                    Key.LoadFromReader(rd);
                    rd.Close();
                    return true;
                }
                else
                {
                    rd.Close();
                    return false;
                }
                
            }
        }

        public List<T> ExecuteList<T>(string Sql, IQueryable QueryParam)
        {
            T Data = default(T);
            List<T> rs = new List<T>();
            IQueryable pm = QueryParam;
            PrepareCommand(Sql, QueryParam);
            using (rd = comm.ExecuteReader())
            {
                while (rd.Read())
                {
                    Data = (T)QueryParam.CreateNewInstance(); //Activator.CreateInstance<T>();
                    ((IQueryable)Data).LoadFromReader(rd);
                    rs.Add(Data);
                }
                rd.Close();
            }
            return rs;
        }

        public void ExecuteUpdate(string Sql, IQueryable QueryParam)
        {
            PrepareCommand(Sql, QueryParam);
            comm.ExecuteNonQuery();
        }

        public void Update(IQueryable QueryParam)
        {
            StringBuilder sql = new StringBuilder();
            sql.Append("UPDATE [").Append(QueryParam._ObjectTableName).Append("] SET ");
            foreach (IDataParameter p in QueryParam.PreparePrameter())
            {
                sql.Append("[").Append(p.ParameterName.Replace("@", "")).Append("] = ").Append(p.ParameterName);
            }
            sql = sql.Remove(sql.Length - 1, 1);
            sql.Append(" WHERE [").Append(QueryParam._PrimaryKeyName).Append("] = @").Append(QueryParam._PrimaryKeyName);
            PrepareCommand(sql.ToString(), QueryParam);
            comm.ExecuteNonQuery();

        }

        public void Delete(IQueryable QueryParam)
        {
            string Sql = "DELETE FROM [" + QueryParam._ObjectTableName + "] WHERE [" + QueryParam._PrimaryKeyName + "] = @" + QueryParam._PrimaryKeyName;
            PrepareCommand(Sql, QueryParam);
            comm.ExecuteNonQuery();
        }


        public int ExecuteCount(string Sql, IQueryable QueryParam)
        {
            PrepareCommand(Sql, QueryParam);
            return (int)comm.ExecuteScalar();
        }

        public void Create(IQueryable QueryParam)
        {
            string sql = QueryParam._InsertSql;
            PrepareCommand(sql, QueryParam);
            comm.ExecuteNonQuery();
        }

        public void OpenTranscation()
        {
            if (conn.State != ConnectionState.Closed)
            {
                trans = conn.BeginTransaction();
            }
        }

        public void Commit()
        {
            trans.Commit();
            trans = null;
        }

        public void RollBack()
        {
            trans.Rollback();
            trans = null;
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            if (trans != null)
            {
                trans.Rollback();
            }
            if (conn.State != ConnectionState.Closed)
            {
                conn.Close();
            }
        }

        #endregion

        private void PrepareCommand(string Sql, IQueryable param)
        {
            if (trans != null)
            {
                comm = new SqlCommand(Sql, conn, trans);
            }
            else
            {
                comm = new SqlCommand(Sql, conn);
            }
            foreach (IDataParameter p in param.PreparePrameter())
            {
                comm.Parameters.Add((SqlParameter)p);
            }
        }
    }
}
